﻿global using WXWorkSvc.Common.Data;

using Microsoft.AspNetCore.Http;
using Microsoft.AspNetCore.Http.Extensions;
using Microsoft.EntityFrameworkCore;
using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;

using System.Net.Http.Json;
using System.Text;
using System.Web;

using WXWorkSvc.Common.Extensions;
using WXWorkSvc.Common.Models;

namespace WXWorkSvc.Third;

public class WXWork3rd
{
    private readonly WXWork3rdConfig _Config;
    private readonly HttpClient _HC;
    private readonly IHttpContextAccessor _Accessor;
    private readonly ILogger<WXWork3rd> _Logger;
    private readonly IServiceProvider _ServiceProvider;
    public WXWork3rd(HttpClient hc, WXWork3rdConfig config, IHttpContextAccessor acc, ILogger<WXWork3rd> logger, IServiceProvider provider)
    {
        _Config = config;
        _HC = hc;
        _HC.BaseAddress = new Uri("https://qyapi.weixin.qq.com");
        _Accessor = acc;
        _Logger = logger;
        _ServiceProvider = provider;
    }

    public string GetOAuthUrl(HttpRequest request, string state)
    {
        var redirectUri = HttpUtility.UrlEncode($"{_Config.ApplicationUrl}/cb/{Convert.ToBase64String(Encoding.UTF8.GetBytes(request.Host.ToString()))}");
        if (request.IsWXBrowse())
            return $"https://open.weixin.qq.com/connect/oauth2/authorize?appid={_Config.SuiteId}&redirect_uri={redirectUri}&response_type=code&scope=snsapi_base&state={state}#wechat_redirect";
        else
            return $"https://login.work.weixin.qq.com/wwlogin/sso/login?login_type=ServiceApp&appid={_Config.AuthSuiteId}&redirect_uri={redirectUri}&state={state}";
    }





    /// <summary>
    /// 扫码登录获取用户Id
    /// </summary>
    /// <param name="isWXBrowse">非微信浏览器，使用AuthStuiteId</param>
    /// <param name="code"></param>
    /// <returns></returns>
    public async Task<ResponseOAuthUser> GetOAuthUserAsync(bool isWXBrowse, string code)
    {
        var ret = await _HC.GetFromJsonAsync<ResponseOAuthUser>($"cgi-bin/service/auth/getuserinfo3rd?suite_access_token={await GetSuiteAccessTokenAsync(!isWXBrowse)}&code={code}");
        ret!.Valid();
        return ret!;
    }

    public async Task SendTextMessageAsync(string corpId, string? userIds, string message)
    {
        if (string.IsNullOrEmpty(userIds))
            return;
        if (userIds.Split('|').Where(ii => !string.IsNullOrEmpty(ii)).Count() == 0)
            return;

        var item = await GetAccessTokenItemAsync(corpId);
        await _HC.PostAsJsonAsync($"cgi-bin/message/send?access_token={item.Token}", new
        {
            touser = userIds,
            agentid = item.AgentId,
            msgtype = "text",
            text = new
            {
                content = message
            }
        });
    }
    /// <summary>
    /// 
    /// </summary>
    /// <param name="userIds">指定接收消息的成员，成员ID列表（多个接收者用‘|’分隔，最多支持1000个）。    特殊情况：指定为"@all"，则向该企业应用的全部成员发送</param>
    /// <param name="message">markdown内容，最长不超过2048个字节，必须是utf8编码</param>
    /// <returns></returns>
    public async Task SendMDMessageAsync(string corpId, string? userIds, string message)
    {

        if (string.IsNullOrEmpty(userIds))
            return;
        if (userIds.Split('|').Where(ii => !string.IsNullOrEmpty(ii)).Count() == 0)
            return;

        var item = await GetAccessTokenItemAsync(corpId);
        await _HC.PostAsJsonAsync($"cgi-bin/message/send?access_token={item.Token}", new
        {
            touser = userIds,
            agentid = item.AgentId,
            msgtype = "markdown",
            markdown = new
            {
                content = message
            }
        });
    }


    private async Task<string> GetAccessTokenAsync(string corpId)
    {
        var item = await GetAccessTokenItemAsync(corpId);
        return item.Token;
    }
    private async Task<TAgent> GetAccessTokenItemAsync(string corpId)
    {
        using var db = getdb();
        var item = await db.Agents.FindAsync(_Config.SuiteId, corpId);

        if (item!.DTExpiresToken < DateTime.Now)
        {
            var rmsg = await _HC.PostAsJsonAsync($"cgi-bin/service/get_corp_token?suite_access_token={await GetSuiteAccessTokenAsync()}", new
            {
                auth_corpid = corpId,
                permanent_code = item.PermanentCode
            });
            rmsg.EnsureSuccessStatusCode();
            var ret = await rmsg.Content.ReadFromJsonAsync<ResponseAccessToken>();
            ret.Valid();
            item.Token = ret!.access_token;
            item.DTExpiresToken = DateTime.Now.AddSeconds(ret.expires_in);
            await db.SaveChangesAsync();
        }
        return item;
    }
    private async Task<TAgent> GetJSTicketAsync(string corpId)
    {
        var value = await GetAccessTokenItemAsync(corpId);
        if (value.DTExpiresTicket < DateTime.Now)
        {
            var ret = await _HC.GetFromJsonAsync<ResponseJsTicket>($"cgi-bin/get_jsapi_ticket?access_token={value.Token}");
            ret.Valid();
            var retAgent = await _HC.GetFromJsonAsync<ResponseJsTicket>($"cgi-bin/ticket/get?access_token={value.Token}&type=agent_config");
            retAgent.Valid();

            using var db = getdb();
            await db.Agents.Where(ii => ii.SuiteId == _Config.SuiteId && ii.CorpId == corpId).ExecuteUpdateAsync(ii => ii.SetProperty(jj => jj.JsTicket, ret!.ticket).SetProperty(jj => jj.AgentJsTicket, retAgent!.ticket).SetProperty(jj => jj.DTExpiresTicket, DateTime.Now.AddSeconds(ret.expires_in - 10)));
        }
        return value;
    }



    private async Task<string> GetSuiteAccessTokenAsync(bool isAuthSuite = false)
    {
        using var db = getdb();
        var item = await db.Suites.FindAsync(isAuthSuite ? _Config.AuthSuiteId : _Config.SuiteId);

        if (item!.DTTokenExpires < DateTime.Now)
        {
            var rmsg = await _HC.PostAsJsonAsync("cgi-bin/service/get_suite_token", new
            {
                suite_id = item.Id,
                suite_secret = item.Secret,
                suite_ticket = item.Ticket
            });

            rmsg.EnsureSuccessStatusCode();
            var ret = await rmsg.Content.ReadFromJsonAsync<ResponseSuiteAccessToken>();
            ret.Valid();

            item.Token = ret!.suite_access_token;
            item.DTTokenExpires = DateTime.Now.AddSeconds(ret.expires_in);
            await db.SaveChangesAsync();
        }
        return item.Token;
    }



    /// <summary>
    /// 
    /// </summary>
    /// <param name="url"></param>
    /// <param name="jsApiList"></param>
    /// <returns></returns>
    public async Task<string> GetAgentJsConfigAsync(HttpRequest request, string corpId, params string[] jsApiList)
    {
        var url = _Accessor.HttpContext!.Request.GetDisplayUrl();
        if (url.ToLower().Contains("localhost"))
            return "";

        var index = url.IndexOf("#");
        if (index > 0)
            url = url.Substring(0, index);


        var item = await GetJSTicketAsync(corpId);
        var noncestr = DateTime.Now.Ticks.ToString();
        var timestamp = noncestr;
        var str = $"jsapi_ticket={item.AgentJsTicket}&noncestr={noncestr}&timestamp={timestamp}&url={url}";

        var agentSign = Encoding.UTF8.GetBytes(str).Sha1Sign();

        if (request.IsWXBrowse())
        {
            str = $"jsapi_ticket={item.JsTicket}&noncestr={noncestr}&timestamp={timestamp}&url={url}";
            var sign = Encoding.UTF8.GetBytes(str).Sha1Sign();

            return @$"
<script src=""https://res.wx.qq.com/open/js/jweixin-1.2.0.js"" referrerpolicy=""origin""></script>
<script src=""https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"" referrerpolicy=""origin""></script>
<script>
var WXReady=false;
wx.config({{beta: true,
    debug: false,
    appId: '{corpId}',
    timestamp: '{timestamp}',
    nonceStr: '{noncestr}', 
    signature: '{sign}',
    jsApiList: ['{string.Join("','", jsApiList)}']
}});

wx.ready(function(){{
    wx.agentConfig({{
        corpid: '{corpId}',
        agentid: '{item.AgentId}', // 必填，企业微信的应用id （e.g. 1000247）
        timestamp:'{timestamp}' , // 必填，生成签名的时间戳
        nonceStr: '{noncestr}', // 必填，生成签名的随机串
        signature: '{agentSign}',// 必填，签名，见附录-JS-SDK使用权限签名算法
        jsApiList: [''], //必填，传入需要使用的接口名称
	    success: function(res) {{
       	    WWOpenData.bind(document.querySelector('ww-open-data'));
        }},
        fail: function(res) {{
//var str=JSON.stringify(res);
//alert(""fail""+str);
            if(res.errMsg.indexOf('function not exist') > -1){{
                alert('版本过低请升级')
            }}
        }}
    }});


}});
</script>
";
        }
        else
            return $@"
<script src=""https://res.wx.qq.com/open/js/jweixin-1.2.0.js"" referrerpolicy=""origin""></script>
<script src=""https://open.work.weixin.qq.com/wwopen/js/jwxwork-1.0.0.js"" referrerpolicy=""origin""></script>
<script>

wx.agentConfig({{
    corpid: '{corpId}',
    agentid: '{item.AgentId}', // 必填，企业微信的应用id （e.g. 1000247）
    timestamp:'{timestamp}' , // 必填，生成签名的时间戳
    nonceStr: '{noncestr}', // 必填，生成签名的随机串
    signature: '{agentSign}',// 必填，签名，见附录-JS-SDK使用权限签名算法
    jsApiList: [''], //必填，传入需要使用的接口名称
	success: function(res) {{
       	WWOpenData.bind(document.querySelector('ww-open-data'));
    }},
    fail: function(res) {{
//var str=JSON.stringify(res);
//alert(""fail""+str);
        if(res.errMsg.indexOf('function not exist') > -1){{
            alert('版本过低请升级')
        }}
    }}
}});

</script>

";


    }





    //#region Auth
    //public async Task CreateAuthAsync(string suiteId, string auth_code)
    //{
    //    var msg = await _HC.PostAsJsonAsync($"cgi-bin/service/get_permanent_code?suite_access_token={await GetSuiteAccessTokenAsync(suiteId)}", new { auth_code });
    //    msg.EnsureSuccessStatusCode();
    //    var jsonStr = await msg.Content.ReadAsStringAsync();
    //    var v = jsonStr.To<ResponseCreateAuth>();
    //    ErrorProcess(v);

    //    using var db = GetDb();
    //    var item = await db.AuthCorps.FirstOrDefaultAsync(ii => ii.AuthCorpId == v.auth_corp_info.corpid);
    //    if (item is null)
    //    {
    //        item = new TAuthCorp { AuthCorpId = v.auth_corp_info.corpid };
    //        db.AuthCorps.Add(item);
    //    }
    //    item.Name = v.auth_corp_info.corp_full_name;

    //    item.AgentId = v.auth_info.agent[0].agentid;
    //    item.PermanentCode = v.permanent_code;
    //    item.DTAuth = DateTime.Now;
    //    item.IsAuth = true;
    //    await db.SaveChangesAsync();

    //    _CorpValues.AddOrUpdate(item.Id, new CorpValue
    //    {
    //        AccessToken = v.access_token,
    //        DTExpiresTicket = DateTime.Now.AddSeconds(v.expires_in),
    //        AuthCorpId = v.auth_corp_info.corpid,
    //        AgentId = v.auth_info.agent[0].agentid
    //    }, (k, va) =>
    //    {
    //        va.AccessToken = v.access_token;
    //        va.DTExpiresTicket = DateTime.Now.AddSeconds(v.expires_in);
    //        va.AuthCorpId = v.auth_corp_info.corpid;
    //        va.AgentId = v.auth_info.agent[0].agentid;
    //        return va;
    //    });

    //    if (!await db.Users.AnyAsync(ii => ii.CorpId == item.Id && ii.UserId == v.auth_user_info.userid))
    //    {
    //        db.Users.Add(new TUser
    //        {
    //            CorpId = item.Id,
    //            UserId = v.auth_user_info.userid,
    //            Roles = item.AuthCorpId == SuiteConfig.CorpId ? "系统管理员" : "管理员"
    //        });
    //        await db.SaveChangesAsync();
    //    }
    //}
    //public async Task<ResponseCorpAuthInfo> GetCorpAuthInfoAsync(string auth_corpid, string permanent_code)
    //{
    //    var msg = await _HC.PostAsJsonAsync($"cgi-bin/service/get_auth_info?suite_access_token={await GetSuiteAccessTokenAsync()}", new { auth_corpid, permanent_code });
    //    msg.EnsureSuccessStatusCode();
    //    var v = await msg.Content.ReadFromJsonAsync<ResponseCorpAuthInfo>();
    //    ErrorProcess(v);
    //    return v!;
    //}
    //#endregion

    private WXDbContext getdb() => _ServiceProvider.CreateScope().ServiceProvider.GetRequiredService<WXDbContext>();
}
